﻿using iTool.Cloud.Center.Model;
using System.Collections.Generic;
using System.Collections.Concurrent;
using Orleans;
using System;
using System.Threading.Tasks;
using System.Linq;
using Orleans.Runtime;
using iTool.Common;
using iTool.Cloud.Center.ServiceProvider.StorageProvider;

namespace iTool.Clustering.Center.ServiceProvider
{
    public class ClusterServerService : Orleans.Grain, IClusterServerService
    {
        private iStorageMembershipMaster membershipMaster;
        private ConcurrentDictionary<string, MembershipOptions> Memberships;
        private ClusterTableVersionOptions ClusterTableVersionOptions;

        public override Task OnActivateAsync()
        {
            var cluster = this.GetPrimaryKeyString();

            this.membershipMaster = iStorage.GetClusterMemberships(cluster);
            this.Memberships = this.membershipMaster.Memberships;
            this.ClusterTableVersionOptions = this.membershipMaster.ClusterTableVersionOptions;

            var result = this.Memberships.Where(item => item.Value.Status == (int)SiloStatus.Dead);
            if (result.Count() > 0)
            {
                foreach (var item in result)
                {
                    this.Memberships.TryRemove(item.Key, out _);
                }
            }

            this.membershipMaster.StartSubjecter();
            // 初始化数据
            return base.OnActivateAsync();
        }

        public async Task CleanupDefunctSiloEntries(DateTimeOffset beforeDate)
        {
            iPrint.Line(String.Format("\niTool> CleanupDefunctSiloEntries {0}.", beforeDate));

            //var result = this.Memberships.Where(item => item.Value.IAmAliveTime < beforeDate && item.Value.Status != (int)SiloStatus.Active);
            var result = this.Memberships.Where(item => item.Value.IAmAliveTime < beforeDate && item.Value.Status != (int)SiloStatus.Active || item.Value.Status == (int)SiloStatus.Dead);

            if (result.Count() > 0)
            {
                foreach (var item in result)
                {
                    this.Memberships.TryRemove(item.Key,out _);
                }
            }
            this.membershipMaster.Upsert();
            await Task.CompletedTask;
        }

        public async Task DeleteMembershipTableEntries(string clusterId)
        {
            this.Memberships.Clear();
            this.NextVersion();
            this.membershipMaster.Upsert();
            await Task.CompletedTask;
        }

        public async Task InitializeMembershipTable(bool tryInitTableVersion)
        {
            await Task.CompletedTask;
        }

        public Task<bool> InsertRow(string key, MembershipOptions entry, ClusterTableVersionOptions tableVersion)
        {

            this.NextVersion();

            if (this.Memberships.ContainsKey(key))
            {
                this.Memberships.Remove(key, out _);
            }

            this.membershipMaster.Upsert();
            return Task.FromResult(this.Memberships.TryAdd(key, entry));
        }

        public Task<MembershipTableOptions> ReadAll()
        {
            var result = new MembershipTableOptions 
            {
                ClusterTableVersionOptions = this.ClusterTableVersionOptions,
                MembershipOptionList = this.Memberships.Values.ToList()
            };

            return Task.FromResult(result);
        }

        public Task<MembershipTableOptions> ReadRow(string key)
        {
            var result = new MembershipTableOptions
            {
                ClusterTableVersionOptions = this.ClusterTableVersionOptions,
                MembershipOptionList = new List<MembershipOptions>()
            };

            if (this.Memberships.TryGetValue(key,out MembershipOptions entry))
            {
                result.MembershipOptionList.Add(entry);
            }

            return Task.FromResult(result);
        }

        public async Task UpdateIAmAlive(string key, DateTime iAmAliveTime)
        {
            if (this.Memberships.TryGetValue(key, out MembershipOptions entry))
            {
                entry.IAmAliveTime = iAmAliveTime;
            }
            this.membershipMaster.Upsert();
            await Task.CompletedTask;
        }

        public Task<bool> UpdateRow(string key, MembershipOptions entry, string etag, ClusterTableVersionOptions tableVersion)
        {
            this.NextVersion();

            if (this.Memberships.ContainsKey(key))
            {
                this.Memberships[key] = entry;
            }

            this.membershipMaster.Upsert();
            return Task.FromResult(true);
        }

        private void NextVersion() 
        {
            this.ClusterTableVersionOptions.Version++;
            this.ClusterTableVersionOptions.VersionEtag = this.ClusterTableVersionOptions.Version.ToString();
        }
    }
}
